package web.dropwizard;

import application.services.ApplicationService;
import com.codahale.metrics.annotation.Timed;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import domain.model.project.Project;
import domain.model.project.ProjectDeveloper;
import domain.model.project.ProjectId;
import domain.model.project.ProjectSCM;
import domain.model.project.support.projectid.ProjectIdBuilder;

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.List;
import java.util.Set;

/**
 * @author Gregory Boissinot
 */
@Path("/projects")
public class ProjectResource {

    private final ApplicationService applicationService;

    public ProjectResource(ApplicationService applicationService) {
        this.applicationService = applicationService;
    }

    @GET
    @Timed
    @Produces(MediaType.APPLICATION_JSON)
    public Response findProjects() {
        return Response.ok(new ProjectList(applicationService.getAllProjectInfo())).build();
    }

    @GET
    @Timed
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/{org}/{name}")
    public Response findProject(@PathParam("org") String org, @PathParam("name") String name) {
        ProjectId projectId = new ProjectIdBuilder(org, name).build();
        return Response.ok(applicationService.getProjectInfo(projectId)).build();
    }

    @PUT
    @Timed
    @Consumes(MediaType.APPLICATION_JSON)
    public Response importProject(Project project) {
        applicationService.importProject(project, true);
        return Response.noContent().build();
    }

    @PUT
    @Timed
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("/{org}/{name}")
    public Response updateProject(@PathParam("org") String org, @PathParam("name") String name, Project project) {
        ProjectId projectId = new ProjectIdBuilder(org, name).build();
        applicationService.updateProject(projectId, project, true);
        return Response.noContent().build();
    }

    @PUT
    @Timed
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("/{org}/{name}/scm")
    public Response updateSCM(@PathParam("org") String org, @PathParam("name") String name, ProjectSCM projectSCM) {
        ProjectId projectId = new ProjectIdBuilder(org, name).build();
        applicationService.updateSCM(projectId, projectSCM, true);
        return Response.noContent().build();
    }

    @PUT
    @Timed
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("/{org}/{name}/developers")
    public Response updateDevelopers(@PathParam("org") String org, @PathParam("name") String name, List<ProjectDeveloper> projectDeveloperList) {
        ProjectId projectId = new ProjectIdBuilder(org, name).build();
        applicationService.updateDevelopers(projectId, projectDeveloperList, true);
        return Response.noContent().build();
    }

    @PUT
    @Timed
    @Path("/{org}/{name}/open")
    public Response openProject(@PathParam("org") String org, @PathParam("name") String name) {
        ProjectId projectId = new ProjectIdBuilder(org, name).build();
        applicationService.openProject(projectId, true);
        return Response.noContent().build();
    }

    @PUT
    @Timed
    @Path("/{org}/{name}/close")
    public Response closeProject(@PathParam("org") String org, @PathParam("name") String name) {
        ProjectId projectId = new ProjectIdBuilder(org, name).build();
        applicationService.closeProject(projectId, true);
        return Response.noContent().build();
    }

    @PUT
    @Timed
    @Path("/syncCIJobs")
    public Response syncCIJobs() {
        applicationService.syncCIJobs();
        return Response.ok().build();
    }

    @GET
    @Timed
    @Path("/allSCM")
    @Produces(MediaType.APPLICATION_JSON)
    public Response findAllSCM() {
        final Set<String> allScmConnectionURL = applicationService.findAllScmConnectionURL();
        return Response.ok().entity(new SCMSet(allScmConnectionURL)).build();
    }

    @JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY)
    private class ProjectList {

        @JsonProperty(required = true)
        private List<Project> projects;

        private ProjectList(List<Project> projects) {
            this.projects = projects;
        }

        public List<Project> getProjects() {
            return projects;
        }
    }

    @JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY)
    private class SCMSet {

        @JsonProperty(required = true)
        private Set<String> urls;

        private SCMSet(Set<String> urls) {
            this.urls = urls;
        }

        public Set<String> getUrls() {
            return urls;
        }
    }
}
